package org.ydeity.lucene.configuration;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.ansj.lucene7.AnsjAnalyzer;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.springframework.data.annotation.Id;
import org.springframework.util.StringUtils;
import org.ydeity.lucene.annotation.FieldType;
import org.ydeity.lucene.annotation.LuceneDocument;
import org.ydeity.lucene.annotation.LuceneField;
import org.ydeity.lucene.exception.LuceneException;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description lucene document 配置
 * @author liuyuan
 * @Date 2020/7/25
 * @Time 10:49 下午
 */
public class LuceneDocumentProperties {

    private Class<?> documentClazz;

    private String coreName;

    private IndexWriterConfig.OpenMode openMode;

    private Class<? extends Analyzer> analyzer = AnsjAnalyzer.class;

    private AnsjAnalyzer.TYPE analyzerType;

    private boolean commit = true;

    private LuceneProperties luceneProperties;

    private Map<String,LuceneFieldProperties> fieldMapping;

    private IdProperties idProperties;

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class IdProperties{

        private String property;

        private FieldType fieldType;
    }

    public LuceneDocumentProperties(Class<?> documentClazz,LuceneProperties luceneProperties) {
        this.documentClazz = documentClazz;
        this.luceneProperties = luceneProperties;
        this.fieldMapping = new HashMap<>();

        this.parser();
        this.parserField();
    }

    private void parser() {
        LuceneDocument documentAnnotation = this.documentClazz.getAnnotation(LuceneDocument.class);

        if(documentAnnotation == null){
            this.defaultDocument();
            return ;
        }

        String coreNameAnnotation = documentAnnotation.coreName();

        if(StringUtils.isEmpty(coreNameAnnotation)){
            this.coreName = this.documentClazz.getSimpleName();
        } else {
            this.coreName = coreNameAnnotation;
        }

        this.openMode = documentAnnotation.openMode();
        this.analyzer = documentAnnotation.analyzer();
        this.analyzerType = documentAnnotation.analyzerType();
        this.commit = documentAnnotation.commit();
    }

    private void parserField(){
        Field[] fields = this.documentClazz.getDeclaredFields();

        for (Field field : fields) {
            this.fieldMapping.put(field.getName(),this.getFieldProperties(field));
        }
    }

    private LuceneFieldProperties getFieldProperties(Field field){
        Id id = field.getAnnotation(Id.class);
        if(id != null){
            IdProperties idPro = new IdProperties();
            idPro.setProperty(field.getName());
            this.idProperties = idPro;
        }

        LuceneField annotation = field.getAnnotation(LuceneField.class);

        if(annotation == null){
            return new LuceneFieldProperties(FieldType.Auto,true,null,null,field.getType());
        }
        return new LuceneFieldProperties(annotation,field.getType());
    }

    private void defaultDocument(){
        this.coreName = this.documentClazz.getSimpleName();
        this.openMode = IndexWriterConfig.OpenMode.APPEND;
        this.analyzer = AnsjAnalyzer.class;
        this.analyzerType = AnsjAnalyzer.TYPE.base_ansj;
    }

    public IndexWriterConfig getIndexWriteConfig(){
        IndexWriterConfig iwConfig = new IndexWriterConfig(this.getAnalyzerInstance());
        // 设置创建索引模式(在原来的索引的基础上创建或新增)
        iwConfig.setOpenMode(this.openMode);
        return iwConfig;
    }

    private Analyzer getAnalyzerInstance(){
        if(AnsjAnalyzer.class.equals(this.analyzer)){
            return new AnsjAnalyzer(this.analyzerType);
        }

        try {
            return this.analyzer.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new LuceneException("document analyzer not support " + this.analyzer);
        }
    }

    public IndexWriter getIndexWriter(){
        IndexWriter indexWriter = null;
        try {
            indexWriter = new IndexWriter(this.getFSDirectory(), this.getIndexWriteConfig());
        } catch (IOException e) {
            throw new LuceneException(e.getMessage());
        }
        return indexWriter;
    }

    private Directory getFSDirectory() {
        try {
            return FSDirectory.open(Paths.get(this.getFileDirectory()));
        } catch (IOException e) {
            throw new LuceneException(e.getMessage());
        }
    }

    private String getFileDirectory(){
        String directory = this.luceneProperties.getDirect() + File.separator + this.coreName;

        File file = new File(directory);
        if(!file.exists()) {
            file.mkdirs();
        }
        return directory;
    }

    public DirectoryReader getDirectoryReader(){
        try {
            return DirectoryReader.open(this.getFSDirectory());
        } catch (IOException e) {
            throw new LuceneException(e.getMessage());
        }
    }

    public IndexSearcher getIndexSearcher(){
        return new IndexSearcher(this.getDirectoryReader());
    }

    public String getCoreName() {
        return coreName;
    }

    public IndexWriterConfig.OpenMode getOpenMode() {
        return openMode;
    }

    public Class<?> getAnalyzer() {
        return analyzer;
    }

    public boolean isCommit() {
        return commit;
    }

    public Map<String, LuceneFieldProperties> getFieldMapping() {
        return fieldMapping;
    }

    public IdProperties getIdProperties() {
        return idProperties;
    }
}
